.586
.model flat,stdcall
option casemap:none

includelib ucrt.lib
includelib legacy_stdio_definitions.lib
includelib User32.lib
includelib Kernel32.lib

ExitProcess PROTO uType:DWORD
extern printf:proc

.data
num dd ?
fmt_num	db '%d', 0
fmt_str db '%s', 0
source db 'abcdef', 0
target db '12345', 0
des1   db 100 dup(?)
.code

; int __cdecl myStrlen(char* source)
; 参数：[ebp + 8] char* source
; 返回值：eax	字符串source长度
myStrlen proc
	push ebp
	mov	 ebp, esp
	push edi			;保护edi
	mov edi, [ebp + 8]	;将source给edi
	xor ecx, ecx		;
	not ecx				;将ecx设置为最大值
	mov al, 0
	cld
	repne scasb			;搜索'\0'的位置
	mov eax, edi		; edi此时存储的是'\0'的下一个位置
	sub eax, [ebp + 8]
	dec eax
	pop edi				;保护edi
	leave
	ret
myStrlen endp


; int __cdecl myStrcmp(char* des, char* src)
; 参数：[ebp + 8] char* des
;	   [ebp + 0ch]	char* src 
; 返回值：eax	如果des == src,返回0，否则返回非0值
myStrcmp proc
		push ebp
		mov ebp, esp
		push edi
		push esi
	
		mov esi, [ebp + 0ch]	; 传递src到esi
		mov edi, [ebp + 8]		; 传递des到edi
		; 获取des的长度
		push edi
		call myStrlen
		add esp, 4
		mov ecx, eax			;将des长度保存在ecx中
		cld
		repe cmpsb				;字符串比较
		je STREQU
		jl STRLESS
		mov	eax, 1
		jmp MYSTRCMP_RETURN
STRLESS:
		mov eax, -1
		jmp MYSTRCMP_RETURN
STREQU:	
		mov eax, 0	
MYSTRCMP_RETURN:

		pop esi
		pop edi
		leave
		ret
myStrcmp endp


; char*  __cdecl myStrcpy(char* des, char* src)
; 参数：[ebp + 8] char* des
;	   [ebp + 0ch]	char* src 
; 返回值：eax	指向des的指针
myStrcpy proc
		push ebp
		mov ebp, esp
		push edi
		push esi

		mov esi, [ebp + 0ch]	; 传递src到esi
		mov edi, [ebp + 8]		; 传递des到edi
		; 获取src长度
		push esi
		call myStrlen
		add esp, 4
		mov ecx, eax		; 将src长度保存到ecx中
		cld
		rep movsb			; 字符串复制
		mov eax, [ebp + 8]
		pop esi
		pop edi
		leave
		ret
myStrcpy endp

; char*  __cdecl myStrcat(char* des, char* src)
; 参数：[ebp + 8] char* des
;	   [ebp + 0ch]	char* src 
; 返回值：eax	指向des的指针
myStrcat proc
		push ebp
		mov ebp, esp
		push edi
		push esi
		
		;先通过scasb找到插入位置
		mov esi, [ebp + 0ch]	;将src给esi
		mov edi, [ebp + 8]		;将des给edi
		xor ecx, ecx			;
		not ecx					;将ecx设置为最大值
		mov al, 0
		cld
		repne scasb				;搜索'\0'的下一个位置
		dec edi					;将edi指向'\0'的位置
		;获取src的长度
		push esi
		call myStrlen
		add esp, 4
		mov ecx, eax			;将src长度存放在ecx中
		;通过movsb将src插入到des后面
		rep movsb	
		
		mov eax, [ebp + 8]
		pop esi
		pop edi
		leave
		ret
myStrcat endp

; char*  __cdecl myStrstr(char* des, char* src)
; 参数：[ebp + 8] char* des
;	   [ebp + 0ch]	char* src 
; 返回值：eax	指向des的指针
;局部变量：	[ebp - 4]	src长度
;			[ebp - 8]   des长度
myStrstr proc
			push ebp
			mov ebp, esp
			push edi
			push esi
			sub esp, 8h		;开辟局部变量
			; 取得src长度
			mov eax, [ebp + 0ch]
			push eax
			call myStrlen
			add esp, 4
			mov [ebp-4], eax ; 存放src长度
			; 取得des长度
			mov eax, [ebp + 8]
			push eax
			call myStrlen
			add esp, 4
			mov [ebp-8], eax ; 存放des长度
			mov eax, [ebp-4] 
			cmp dword ptr [ebp-8], eax
			jb MYSTRSTR_RET_NULL
			;查找子串
			mov edi, [ebp+8]	;目标des地址
			mov esi, [ebp+0ch]	;子串src地址
			mov ecx, [ebp-8]	;
			sub ecx, [ebp-4]	;(des长度-src长度+1)作为计数器
			inc ecx				;
MYSTRSTR_LOOP1:
			push ecx			;保存	ecx
			push edi			;		edi
			push esi			;		esi
			mov ecx, [ebp - 4]	;将src长度放在ecx中
			cld
			repe cmpsb			;使用cmpsb指令判断子串
			je MYSTRSTR_RET_EDI
			pop esi				;恢复	esi
			pop edi				;		edi
			pop ecx				;		ecx
			dec ecx				;计数器减1
			inc edi				;des下标加1
			loop MYSTRSTR_LOOP1
MYSTRSTR_RET_NULL:
			mov eax, 0
			jmp MYSTRSTR_RET
MYSTRSTR_RET_EDI:
			pop esi		;恢复	esi
			pop edi		;		edi
			pop ecx		;		ecx
			mov eax, edi
MYSTRSTR_RET:
			add esp, 8h	;释放局部变量
			pop esi
			pop edi
			leave
			ret
myStrstr endp

;###################################
;  主函数
;###################################
main proc
	lea eax, source
	push eax
	lea eax, target
	push eax
	call myStrcat
	add esp, 4
	
	push eax
	lea eax, fmt_str
	push eax
	call printf
	add esp, 8
	
	push 0
	call ExitProcess
main endp
end